home *** CD-ROM | disk | FTP | other *** search
/ QRZ! Ham Radio 8 / QRZ Ham Radio Callsign Database - Volume 8.iso / mac / files / t_sys5 / unixcpio.gz / unixnet.cpio / ip.c < prev    next >
C/C++ Source or Header  |  1994-07-11  |  10KB  |  388 lines

  1. /* Upper half of IP, consisting of send/receive primitives, including
  2.  * fragment reassembly, for higher level protocols.
  3.  * Not needed when running as a standalone gateway.
  4.  */
  5. #define    TLB    30 * (1000/MSPTICK)    /* Reassembly limit time */
  6. #include "global.h"
  7. #include "mbuf.h"
  8. #include "timer.h"
  9. #include "internet.h"
  10. #include "iface.h"
  11. #include "ip.h"
  12. #include "icmp.h"
  13.  
  14. void ip_recv();
  15.  
  16. char ip_ttl = MAXTTL;    /* Default time-to-live for IP datagrams */
  17.  
  18. struct reasm *reasmq;
  19.  
  20. #define    INSERT    0
  21. #define    APPEND    1
  22. #define    PREPEND    2
  23.  
  24. /* Send an IP datagram. Modeled after the example interface on p 32 of
  25.  * RFC 791
  26.  */
  27. int
  28. ip_send(source,dest,protocol,tos,ttl,bp,length,id,df)
  29. int32 source;            /* source address */
  30. int32 dest;            /* Destination address */
  31. char protocol;            /* Protocol */
  32. char tos;            /* Type of service */
  33. char ttl;            /* Time-to-live */
  34. struct mbuf *bp;        /* Data portion of datagram */
  35. int16 length;            /* Optional length of data portion */
  36. int16 id;            /* Optional identification */
  37. char df;            /* Don't-fragment flag */
  38. {
  39.     struct mbuf *htonip(),*tbp;
  40.     struct ip ip;        /* Pointer to IP header */
  41.     static int16 id_cntr;    /* Datagram serial number */
  42.     int ip_route();        /* Datagram router */
  43.  
  44.     if(length == 0 && bp != NULLBUF)
  45.         length = len_mbuf(bp);
  46.     if(id == 0)
  47.         id = id_cntr++;        
  48.     if(ttl == 0)
  49.         ttl = ip_ttl;
  50.  
  51.     /* Fill in IP header */
  52.     ip.tos = tos;
  53.     ip.length = IPLEN + length;
  54.     ip.id = id;
  55.     if(df)
  56.         ip.fl_offs = DF;
  57.     else
  58.         ip.fl_offs = 0;
  59.     ip.ttl = ttl;
  60.     ip.protocol = protocol;
  61.     ip.source = source;
  62.     ip.dest = dest;
  63.     ip.optlen = 0;
  64.     if((tbp = htonip(&ip,bp)) == NULLBUF){
  65.         free_p(bp);
  66.         return -1;
  67.     }
  68.     return ip_route(tbp,0);        /* Toss it to the router */
  69. }
  70.  
  71. /* Reassemble incoming IP fragments and dispatch completed datagrams
  72.  * to the proper transport module
  73.  */
  74. void
  75. ip_recv(ip,bp,rxbroadcast)
  76. struct ip *ip;        /* Extracted IP header */
  77. struct mbuf *bp;    /* Data portion */
  78. char rxbroadcast;    /* True if received on subnet broadcast address */
  79. {
  80.     struct mbuf *fraghandle();
  81.     void (*recv)();    /* Function to call with completed datagram */
  82.     void tcp_input(),udp_input(),icmp_input();
  83.  
  84.     /* Initial check for protocols we can't handle */
  85.     switch(uchar(ip->protocol)){
  86.     case TCP_PTCL:
  87.         recv = tcp_input;
  88.         break;
  89.     case UDP_PTCL:
  90.         recv = udp_input;
  91.         break;
  92.     case ICMP_PTCL:
  93.         recv = icmp_input;
  94.         break;
  95.     default:
  96.         /* Send an ICMP Protocol Unknown response... */
  97.         ip_stats.badproto++;
  98.         /* ...unless it's a broadcast */
  99.         if(!rxbroadcast){
  100.             icmp_output(ip,bp,DEST_UNREACH,PROT_UNREACH,(union icmp_args *)NULL);
  101.         }
  102.         free_p(bp);
  103.         return;
  104.     }
  105.     /* If we have a complete packet, call the next layer
  106.      * to handle the result. Note that fraghandle passes back
  107.      * a length field that does NOT include the IP header
  108.      */
  109.     if((bp = fraghandle(ip,bp)) != NULLBUF)
  110.         (*recv)(bp,ip->protocol,ip->source,ip->dest,ip->tos,
  111.             ip->length - (IPLEN + ip->optlen),rxbroadcast);
  112. }
  113. /* Process IP datagram fragments
  114.  * If datagram is complete, return it with ip->length containing the data
  115.  * length (MINUS header); otherwise return NULLBUF
  116.  */
  117. static
  118. struct mbuf *
  119. fraghandle(ip,bp)
  120. struct ip *ip;        /* IP header, host byte order */
  121. struct mbuf *bp;    /* The fragment itself */
  122. {
  123.     void ip_timeout(),freefrag(),free_reasm();
  124.     struct reasm *lookup_reasm(),*creat_reasm();
  125.     register struct reasm *rp; /* Pointer to reassembly descriptor */
  126.     struct frag *lastfrag,*nextfrag,*tfp,*newfrag();
  127.     struct mbuf *tbp;
  128.     int16 i;
  129.     int16 offset;        /* Index of first byte in fragment */
  130.     int16 last;        /* Index of first byte beyond fragment */
  131.     char mf;        /* 1 if not last fragment, 0 otherwise */
  132.  
  133.     offset = (ip->fl_offs & F_OFFSET) << 3;    /* Convert to bytes */
  134.     last = offset + ip->length - (IPLEN + ip->optlen);
  135.     mf = (ip->fl_offs & MF) ? 1 : 0;
  136.  
  137.     rp = lookup_reasm(ip);
  138.     if(offset == 0 && !mf){
  139.         /* Complete datagram received. Discard any earlier fragments */
  140.         if(rp != NULLREASM)
  141.             free_reasm(rp);
  142.  
  143.         return bp;
  144.     }
  145.     if(rp == NULLREASM){
  146.         /* First fragment; create new reassembly descriptor */
  147.         if((rp = creat_reasm(ip)) == NULLREASM){
  148.             /* No space for descriptor, drop fragment */
  149.             free_p(bp);
  150.             return NULLBUF;
  151.         }
  152.     }
  153.     /* Keep restarting timer as long as we keep getting fragments */
  154.     stop_timer(&rp->timer);
  155.     start_timer(&rp->timer);
  156.  
  157.     /* If this is the last fragment, we now know how long the
  158.      * entire datagram is; record it
  159.      */
  160.     if(!mf)
  161.         rp->length = last;
  162.  
  163.     /* Set nextfrag to the first fragment which begins after us,
  164.      * and lastfrag to the last fragment which begins before us
  165.      */
  166.     lastfrag = NULLFRAG;
  167.     for(nextfrag = rp->fraglist;nextfrag != NULLFRAG;nextfrag = nextfrag->next){
  168.         if(nextfrag->offset > offset)
  169.             break;
  170.         lastfrag = nextfrag;
  171.     }
  172.     /* Check for overlap with preceeding fragment */
  173.     if(lastfrag != NULLFRAG  && offset < lastfrag->last){
  174.         /* Strip overlap from new fragment */
  175.         i = lastfrag->last - offset;
  176.         pullup(&bp,NULLCHAR,i);
  177.         if(bp == NULLBUF)
  178.             return NULLBUF;    /* Nothing left */
  179.         offset += i;
  180.     }
  181.     /* Look for overlap with succeeding segments */
  182.     for(; nextfrag != NULLFRAG; nextfrag = tfp){
  183.         tfp = nextfrag->next;    /* save in case we delete fp */
  184.  
  185.         if(nextfrag->offset >= last)
  186.             break;    /* Past our end */
  187.         /* Trim the front of this entry; if nothing is
  188.          * left, remove it.
  189.          */
  190.         i = last - nextfrag->offset;
  191.         pullup(&nextfrag->buf,NULLCHAR,i);
  192.         if(nextfrag->buf == NULLBUF){
  193.             /* superseded; delete from list */
  194.             if(nextfrag->prev != NULLFRAG)
  195.                 nextfrag->prev->next = nextfrag->next;
  196.             else
  197.                 rp->fraglist = nextfrag->next;
  198.             if(tfp->next != NULLFRAG)
  199.                 nextfrag->next->prev = nextfrag->prev;
  200.             freefrag(nextfrag);
  201.         } else
  202.             nextfrag->offset = last;
  203.     }
  204.     /* Lastfrag now points, as before, to the fragment before us;
  205.      * nextfrag points at the next fragment. Check to see if we can
  206.      * join to either or both fragments.
  207.      */
  208.     i = INSERT;
  209.     if(lastfrag != NULLFRAG && lastfrag->last == offset)
  210.         i |= APPEND;
  211.     if(nextfrag != NULLFRAG && nextfrag->offset == last)
  212.         i |= PREPEND;
  213.     switch(i){
  214.     case INSERT:    /* Insert new desc between lastfrag and nextfrag */
  215.         tfp = newfrag(offset,last,bp);
  216.         tfp->prev = lastfrag;
  217.         tfp->next = nextfrag;
  218.         if(lastfrag != NULLFRAG)
  219.             lastfrag->next = tfp;    /* Middle of list */
  220.         else
  221.             rp->fraglist = tfp;    /* First on list */
  222.         if(nextfrag != NULLFRAG)
  223.             nextfrag->prev = tfp;
  224.         break;
  225.     case APPEND:    /* Append to lastfrag */
  226.         append(&lastfrag->buf,bp);
  227.         lastfrag->last = last;    /* Extend forward */
  228.         break;
  229.     case PREPEND:    /* Prepend to nextfrag */
  230.         tbp = nextfrag->buf;
  231.         nextfrag->buf = bp;
  232.         append(&nextfrag->buf,tbp);
  233.         nextfrag->offset = offset;    /* Extend backward */
  234.         break;
  235.     case (APPEND|PREPEND):
  236.         /* Consolidate by appending this fragment and nextfrag
  237.          * to lastfrag and removing the nextfrag descriptor
  238.          */
  239.         append(&lastfrag->buf,bp);
  240.         append(&lastfrag->buf,nextfrag->buf);
  241.         nextfrag->buf = NULLBUF;
  242.         lastfrag->last = nextfrag->last;
  243.  
  244.         /* Finally unlink and delete the now unneeded nextfrag */
  245.         lastfrag->next = nextfrag->next;
  246.         if(nextfrag->next != NULLFRAG)
  247.             nextfrag->next->prev = lastfrag;
  248.         freefrag(nextfrag);
  249.         break;
  250.     }
  251.     if(rp->fraglist->offset == 0 && rp->fraglist->next == NULLFRAG 
  252.         && rp->length != 0){
  253.         /* We've gotten a complete datagram, so extract it from the
  254.          * reassembly buffer and pass it on.
  255.          */
  256.         bp = rp->fraglist->buf;
  257.         rp->fraglist->buf = NULLBUF;
  258.         /* Tell IP the entire length */
  259.         ip->length = rp->length + (IPLEN + ip->optlen);
  260.         free_reasm(rp);
  261.         return bp;
  262.     } else
  263.         return NULLBUF;
  264. }
  265. static struct reasm *
  266. lookup_reasm(ip)
  267. struct ip *ip;
  268. {
  269.     register struct reasm *rp;
  270.  
  271.     for(rp = reasmq;rp != NULLREASM;rp = rp->next){
  272.         if(ip->source == rp->source && ip->dest == rp->dest
  273.          && ip->protocol == rp->protocol && ip->id == rp->id)
  274.             return rp;
  275.     }
  276.     return NULLREASM;
  277. }
  278. #ifdef    FOO
  279. static
  280. int16
  281. hash_reasm(source,dest,protocol,id)
  282. int32 source;
  283. int32 dest,
  284. char protocol;
  285. int16 id;
  286. {
  287.     register int16 hval;
  288.  
  289.     hval = loword(source);
  290.     hval ^= hiword(source);
  291.     hval ^= loword(dest);
  292.     hval ^= hiword(dest);
  293.     hval ^= uchar(protocol);
  294.     hval ^= id;
  295.     hval %= RHASH;
  296.     return hval;
  297. }
  298. #endif
  299. /* Create a reassembly descriptor,
  300.  * put at head of reassembly list
  301.  */
  302. static struct reasm *
  303. creat_reasm(ip)
  304. register struct ip *ip;
  305. {
  306.     register struct reasm *rp;
  307.     void ip_timeout();
  308.  
  309.     if((rp = (struct reasm *)calloc(1,sizeof(struct reasm))) == NULLREASM)
  310.         return rp;    /* No space for descriptor */
  311.     rp->source = ip->source;
  312.     rp->dest = ip->dest;
  313.     rp->id = ip->id;
  314.     rp->protocol = ip->protocol;
  315.     rp->timer.start = TLB;
  316.     rp->timer.func = ip_timeout;
  317.     rp->timer.arg = (char *)rp;
  318.  
  319.     rp->next = reasmq;
  320.     if(rp->next != NULLREASM)
  321.         rp->next->prev = rp;
  322.     reasmq = rp;
  323.     return rp;
  324. }
  325.  
  326. /* Free all resources associated with a reassembly descriptor */
  327. static void
  328. free_reasm(rp)
  329. register struct reasm *rp;
  330. {
  331.     register struct frag *fp;
  332.  
  333.     stop_timer(&rp->timer);
  334.     /* Remove from list of reassembly descriptors */
  335.     if(rp->prev != NULLREASM)
  336.         rp->prev->next = rp->next;
  337.     else
  338.         reasmq = rp->next;
  339.     if(rp->next != NULLREASM)
  340.         rp->next->prev = rp->prev;
  341.     /* Free any fragments on list, starting at beginning */
  342.     while((fp = rp->fraglist) != NULLFRAG){
  343.         rp->fraglist = fp->next;
  344.         free_p(fp->buf);
  345.         free((char *)fp);
  346.     }
  347.     free((char *)rp);
  348. }
  349.  
  350. /* Handle reassembly timeouts by deleting all reassembly resources */
  351. static void
  352. ip_timeout(arg)
  353. int *arg;
  354. {
  355.     register struct reasm *rp;
  356.  
  357.     rp = (struct reasm *)arg;
  358.     free_reasm(rp);
  359. }
  360. /* Create a fragment */
  361. static
  362. struct frag *
  363. newfrag(offset,last,bp)
  364. int16 offset,last;
  365. struct mbuf *bp;
  366. {
  367.     struct frag *fp;
  368.  
  369.     if((fp = (struct frag *)calloc(1,sizeof(struct frag))) == NULLFRAG){
  370.         /* Drop fragment */
  371.         free_p(bp);
  372.         return NULLFRAG;
  373.     }
  374.     fp->buf = bp;
  375.     fp->offset = offset;
  376.     fp->last = last;
  377.     return fp;
  378. }
  379. /* Delete a fragment, return next one on queue */
  380. static
  381. void
  382. freefrag(fp)
  383. struct frag *fp;
  384. {
  385.     free_p(fp->buf);
  386.     free((char *)fp);
  387. }
  388.